/*
* MyPromise
* 尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/

class MyPromise {
  constructor(executor) {
    // 初始状态为“pending”
    this.state = 'pending'
    // 成功的值和失败的错误信息
    this.value = undefined
    this.reason = undefined
    // 成功的回调函数组合和失败的回调组合,因为在promise结束之前可能有多个回调添加到上面
    this.onResolvedCallback = []
    this.onRejectedCallback = []
    const resolve = (value) => {
      // 状态一旦确定就不能再改变
      if (this.state !== 'pending') return
      this.state = 'fulfilled'
      this.value = value
      // 依次执行回调
      while (this.onResolvedCallback.length) this.onResolvedCallback.shift()(this.value)
    }
    const reject = (reason) => {
      if (this.state !== 'pending') return
      this.state = 'rejected'
      this.reason = reason
      while (this.onRejectedCallback.length) this.onRejectedCallback.shift()(this.reason)
    }
    // 执行promise的resolve和reject方法,有可能出错,所以用try/catch包裹起来,并且在出错后reject出catch的信息，结束掉
    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }
  // then方法，有两个参数onFulfilled和onRejected
  then(onFulfilled, onRejected) {
    // onFulfilled如果不是函数，就忽略onFulfilled，直接返回value
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    // onRejected如果不是函数，就忽略onRejected，直接扔出错误
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
    // 声明返回的promise2，新建一个新的promise实例，解决链式调用
    const promise2 = new MyPromise((resolve, reject) => {
      // 成功回调函数
      const onFulfilledFunc = () => {
        try {
          const x = onFulfilled(this.value)
          // resolvePromise函数，处理自己return的promise和默认的promise2的关系
          resolvePromise(promise2, x, resolve, reject)
        } catch (error) {
          reject(error)
        }
      }

      // 失败回调函数
      const onRejectedFunc = () => {
        try {
          const x = onRejected(this.reason)
          resolvePromise(promise2, x, resolve, reject)
        } catch (error) {
          reject(error)
        }
      }

      // 这里使用settimeout解决异步编程的问题，因为在声明promise2时还不能使用它，所以放入执行栈异步调用

      // 状态为fulfilled时执行onFulfilled函数，传入终值value
      if (this.state === 'fulfilled') {
        // setTimeout实现异步
        setTimeout(onFulfilledFunc, 0)
      }
      // 状态为rejected时执行onRejected函数，传入据因reason
      if (this.state === 'rejected') {
        // 异步
        setTimeout(onRejectedFunc, 0)
      }
      // 状态为pending时
      if (this.state === 'pending') {
        // onFulfilled存入到成功数组
        this.onResolvedCallback.push(() => {
          // 异步
          setTimeout(onFulfilledFunc, 0)
        })
        // onRejected存入到失败数组
        this.onRejectedCallback.push(() => {
          // 异步
          setTimeout(onRejectedFunc, 0)
        })
      }
    })
    // 返回promise2，完成链式
    return promise2
  }
  catch(fn) {
    return this.then(null, fn)
  }
  finaly(fn) {
    // 如果finaly里面返回一个异步函数，那么我们就将这个异步函数放到resolve里面执行，等待这个异步函数执行完毕在返回promise执行结果
    return this.then(value => {
      return MyPromise.resolve(fn()).then(() => value)
    }, reason => {
      return MyPromise.resolve(fu()).then(() => { throw reason })
    })
  }
}
function resolvePromise(promise2, x, resolve, reject) {
  // 循环引用报错，上一个promise的返回结果是其自身
  if (x === promise2) {
    // reject报错
    return reject(new TypeError('Chaining cycle detected for promise #<MyPromise>'))
  }
  // 防止多次调用
  let called
  // x不是null 且x是对象或者函数
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      // 规范规定，当x为函数或对象时，需要将x.then赋值给then
      const then = x.then
      // 如果then是函数，就默认是promise了
      if (typeof then === 'function') {
        then.call(x, y => {
          // 成功和失败只能调用一个
          if (called) return
          called = true
          // resolve的结果依旧是promise，就继续解析
          resolvePromise(promise2, y, resolve, reject)
        }, err => {
          // 成功和失败只能调用一个
          if (called) return
          called = true
          // 失败就直接reject
          reject(err)
        })
      } else {
        // 直接调用成功即可
        resolve(x)
      }
    } catch (error) {
      // 上面执行失败也认为是失败的
      // 同样只执行一次
      if (called) return
      called = true
      reject(error)
    }
  } else {
    // x为一普通值就直接返回
    resolve(x)
  }
}
// resolve方法
MyPromise.resolve = function(val) {
  return new MyPromise((resolve, reject) => {
    resolve(val)
  })
}
// reject方法
MyPromise.reject = function(val) {
  return new MyPromise((resolve, reject) => {
    reject(val)
  })
}
// race方法
MyPromise.race = function(promises) {
  return new MyPromise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      if (promises[i] instanceof MyPromise) {
        promises[i].then(resolve, reject)
      } else {
        MyPromise.resolve(promises[i]).then(resolve, reject)
      }
    }
  })
}
// all方法(获取所有的promise，都执行then，把结果放到数组，一起返回)
MyPromise.all = function(promises) {
  const result = []
  
  return new MyPromise((resolve, reject) => {
    function processData(index, data) {
      result[index] = data
      if (result.length === promises.length) {
        resolve(result)
      }
    }

    for (let i = 0; i < promises.length; i++) {
      const current = promises[i]
      // 如果数组中是一个promise对象，那么就直接调用它的then方法，返回执行结果
      if (current instanceof MyPromise) {
        current.then(value => processData(i, value), reason => reject(reason))
      } else {
        // 否则就直接返回这个当前值
        processData(i, current)
      }
    }
  })
}


module.exports = MyPromise